{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "tuOe1ymfHZPu"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qFdPvlXBOdUN"
      },
      "source": [
        "# テンソルの基礎"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/tensor\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\"> TensorFlow.orgで表示</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\"> Google Colab で実行</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示{</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード/a0}</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AL2hzxorJiWy"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import numpy as np"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VQ3s2J8Vgowq"
      },
      "source": [
        "テンソルは `dtype` と呼ばれる均一型の多次元配列です。サポートされているすべての `dtypes` は、`tf.dtypes.DType` で確認できます。\n",
        "\n",
        "[NumPy](https://numpy.org/devdocs/user/quickstart.html) で言えば、テンソルは `np.arrays`（のようなもの）とすることができます。\n",
        "\n",
        "すべてのテンソルは、Python の数値や文字列と同じように不変です。つまり、テンソルのコンテンツを更新することは不可能で、新しいテンソルのみを作成できます。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DRK5-9EpYbzG"
      },
      "source": [
        "## 基礎\n",
        "\n",
        "基本的なテンソルを作成してみましょう。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uSHRFT6LJbxq"
      },
      "source": [
        "次は、「スカラー」または「階数 0」のテンソルです。スカラーには単一の値のみが含まれ、「軸」は存在しません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d5JcgLFR6gHv"
      },
      "outputs": [],
      "source": [
        "# This will be an int32 tensor by default; see \"dtypes\" below.\n",
        "rank_0_tensor = tf.constant(4)\n",
        "print(rank_0_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tdmPAn9fWYs5"
      },
      "source": [
        "「ベクトル」または「階数 1」テンソルは、値のリストとして考えられます。1 ベクトルは 1 つの軸です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oZos8o_R6oE7"
      },
      "outputs": [],
      "source": [
        "# Let's make this a float tensor.\n",
        "rank_1_tensor = tf.constant([2.0, 3.0, 4.0])\n",
        "print(rank_1_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G3IJG-ug_H4u"
      },
      "source": [
        "「行列」または「階数 2」テンソルには軸が 2 つあります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cnOIA_xb6u0M"
      },
      "outputs": [],
      "source": [
        "# If we want to be specific, we can set the dtype (see below) at creation time\n",
        "rank_2_tensor = tf.constant([[1, 2],\n",
        "                             [3, 4],\n",
        "                             [5, 6]], dtype=tf.float16)\n",
        "print(rank_2_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "19m72qEPkfxi"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>スカラー, 形状: <code>[]</code>\n",
        "</th>\n",
        "  <th>ベクトル, 形状: <code>[3]</code>\n",
        "</th>\n",
        "  <th>行列, 形状: <code>[3, 2]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td>    <img src=\"images/tensor/scalar.png\" alt=\"A scalar, the number 4\">\n",
        "</td>\n",
        "  <td>    <img src=\"images/tensor/vector.png\" alt=\"The line with 3 sections, each one containing a number.\">\n",
        "</td>\n",
        "  <td>    <img src=\"images/tensor/matrix.png\" alt=\"A 3x2 grid, with each cell containing a number.\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fjFvzcn4_ehD"
      },
      "source": [
        "テンソルにはさらに軸があります。次は、3 軸のテンソルです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sesW7gw6JkXy"
      },
      "outputs": [],
      "source": [
        "# There can be an arbitrary number of\n",
        "# axes (sometimes called \"dimensions\")\n",
        "rank_3_tensor = tf.constant([\n",
        "  [[0, 1, 2, 3, 4],\n",
        "   [5, 6, 7, 8, 9]],\n",
        "  [[10, 11, 12, 13, 14],\n",
        "   [15, 16, 17, 18, 19]],\n",
        "  [[20, 21, 22, 23, 24],\n",
        "   [25, 26, 27, 28, 29]],])\n",
        "                    \n",
        "print(rank_3_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rM2sTGIkoE3S"
      },
      "source": [
        "3 軸以上のテンソルを視覚化する方法はたくさんあります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NFiYfNMMhDgL"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th colspan=\"3\">3 軸テンソル, 形状: <code>[3, 2, 5]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td>    <img src=\"images/tensor/3-axis_numpy.png\">\n",
        "</td>\n",
        "  <td>    <img src=\"images/tensor/3-axis_front.png\">\n",
        "</td>\n",
        "  <td>    <img src=\"images/tensor/3-axis_block.png\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oWAc0U8OZwNb"
      },
      "source": [
        "`np.array` または `tensor.numpy` メソッドを使用して、テンソルを NumPy 配列に変換できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "J5u6_6ZYaS7B"
      },
      "outputs": [],
      "source": [
        "np.array(rank_2_tensor)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "c6Taz2gIaZeo"
      },
      "outputs": [],
      "source": [
        "rank_2_tensor.numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hnz19F0ocEKD"
      },
      "source": [
        "テンソルには、通常、浮動小数点型や整数型が含まれますが、次のようなほかの型も含まれます。\n",
        "\n",
        "- 複素数\n",
        "- 文字列\n",
        "\n",
        "基本の `tf.Tensor` クラスには、「矩形」を成すテンソルが必要です。つまり各要素は、各軸に沿って同じサイズになります。ただし、次のように、異なる形状を処理できる特殊なテンソルもあります。\n",
        "\n",
        "- 不規則（以下の [RaggedTensor](#ragged_tensors) を参照）\n",
        "- スパース（以下の [SparseTensor](#sparse_tensors) を参照）"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SDC7OGeAIJr8"
      },
      "source": [
        "テンソルには、加算、要素ごとの乗算、および行列の乗算などの基本的な計算を実行できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-DTkjwDOIIDa"
      },
      "outputs": [],
      "source": [
        "a = tf.constant([[1, 2],\n",
        "                 [3, 4]])\n",
        "b = tf.constant([[1, 1],\n",
        "                 [1, 1]]) # Could have also said `tf.ones([2,2])`\n",
        "\n",
        "print(tf.add(a, b), \"\\n\")\n",
        "print(tf.multiply(a, b), \"\\n\")\n",
        "print(tf.matmul(a, b), \"\\n\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2smoWeUz-N2q"
      },
      "outputs": [],
      "source": [
        "print(a + b, \"\\n\") # element-wise addition\n",
        "print(a * b, \"\\n\") # element-wise multiplication\n",
        "print(a @ b, \"\\n\") # matrix multiplication"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S3_vIAl2JPVc"
      },
      "source": [
        "テンソルはあらゆる種類の演算に使用されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Gp4WUYzGIbnv"
      },
      "outputs": [],
      "source": [
        "c = tf.constant([[4.0, 5.0], [10.0, 1.0]])\n",
        "\n",
        "# Find the largest value\n",
        "print(tf.reduce_max(c))\n",
        "# Find the index of the largest value\n",
        "print(tf.argmax(c))\n",
        "# Compute the softmax\n",
        "print(tf.nn.softmax(c))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NvSAbowVVuRr"
      },
      "source": [
        "## 形状について"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hkaBIqkTCcGY"
      },
      "source": [
        "テンソルには形状があり、次のような用語が使用されます。\n",
        "\n",
        "- **形状**: テンソルの各次元の長さ（要素の数）。\n",
        "- **階数**: テンソルの次元数。スカラーは階数 0、ベクトルは階数 1、行列は階数 2 となります。\n",
        "- **軸**または**次元**: テンソルの特定の次元。\n",
        "- **サイズ**: テンソル内の項目の総数。生成された形状ベクトル\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E9L3-kCQq2f6"
      },
      "source": [
        "注意: 「2 次元のテンソル」と記述されることもありますが、階数 2 のテンソルは、通常 2 次元形状ではありません。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VFOyG2tn8LhW"
      },
      "source": [
        "テンソルと `tf.TensorShape` オブジェクトには、次にアクセスするための便利なプロパティがあります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RyD3yewUKdnK"
      },
      "outputs": [],
      "source": [
        "rank_4_tensor = tf.zeros([3, 2, 4, 5])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oTZZW9ziq4og"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th colspan=\"2\">階数 4 テンソル, 形状: <code>[3, 2, 4, 5]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/shape.png\" alt=\"A tensor shape is like a vector.\">\n",
        "</td>\n",
        "<td> <img src=\"images/tensor/4-axis_block.png\" alt=\"A 4-axis tensor\">\n",
        "</td>\n",
        "  </tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MHm9vSqogsBk"
      },
      "outputs": [],
      "source": [
        "print(\"Type of every element:\", rank_4_tensor.dtype)\n",
        "print(\"Number of dimensions:\", rank_4_tensor.ndim)\n",
        "print(\"Shape of tensor:\", rank_4_tensor.shape)\n",
        "print(\"Elements along axis 0 of tensor:\", rank_4_tensor.shape[0])\n",
        "print(\"Elements along the last axis of tensor:\", rank_4_tensor.shape[-1])\n",
        "print(\"Total number of elements (3*2*4*5): \", tf.size(rank_4_tensor).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bQmE_Vx5JilS"
      },
      "source": [
        "軸は通常、そのインデックスで参照されますが、それぞれの意味を常に把握しておく必要があります。多くの場合、軸はグローバルからローカルに順序付けられています。バッチ軸を先頭に、空間次元、そして最後に各位置の特徴量が続きます。こうすることで、特徴ベクトルは連続したメモリ領域となります。\n",
        "\n",
        "<table>\n",
        "<tr>\n",
        "<th>典型的な軸の順序</th>\n",
        "</tr>\n",
        "<tr>\n",
        "    <td> <img src=\"images/tensor/shape2.png\" alt=\"Keep track of what each axis is. A 4-axis tensor might be: Batch, Width, Height, Freatures\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FlPoVvJS75Bb"
      },
      "source": [
        "## インデックス作成"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "apOkCKqCZIZu"
      },
      "source": [
        "### 単軸のインデックス作成\n",
        "\n",
        "TensorFlow は、[Python でのリストまたは文字列のインデックス](https://docs.python.org/3/tutorial/introduction.html#strings)と同様の標準的な Python インデックスルールや numpy インデックスの基本ルールを使用しています。\n",
        "\n",
        "- インデックスは `0` から開始\n",
        "- 負のインデックスは後ろ側から逆順に数える\n",
        "- スライスにコロン `:` を使用 -  `start:stop:step`\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SQ-CrJxLXTIM"
      },
      "outputs": [],
      "source": [
        "rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])\n",
        "print(rank_1_tensor.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mQYYL56PXSak"
      },
      "source": [
        "スカラーを使用してインデックスを作成すると、次元が削除されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "n6tqHciOWMt5"
      },
      "outputs": [],
      "source": [
        "print(\"First:\", rank_1_tensor[0].numpy())\n",
        "print(\"Second:\", rank_1_tensor[1].numpy())\n",
        "print(\"Last:\", rank_1_tensor[-1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qJLHU_a2XwpG"
      },
      "source": [
        "`:` スライスでインデックスを作成すると、次元が維持されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "giVPPcfQX-cu"
      },
      "outputs": [],
      "source": [
        "print(\"Everything:\", rank_1_tensor[:].numpy())\n",
        "print(\"Before 4:\", rank_1_tensor[:4].numpy())\n",
        "print(\"From 4 to the end:\", rank_1_tensor[4:].numpy())\n",
        "print(\"From 2, before 7:\", rank_1_tensor[2:7].numpy())\n",
        "print(\"Every other item:\", rank_1_tensor[::2].numpy())\n",
        "print(\"Reversed:\", rank_1_tensor[::-1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "elDSxXi7X-Bh"
      },
      "source": [
        "### 多軸のインデックス作成"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Cgk0uRUYZiai"
      },
      "source": [
        "階数の高いテンソルは、複数のインデックスを渡してインデックス化されます。\n",
        "\n",
        "単軸と全く同じルールが各軸に個別に適用されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Tc5X_WlsZXmd"
      },
      "outputs": [],
      "source": [
        "print(rank_2_tensor.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w07U9vq5ipQk"
      },
      "source": [
        "各インデックスに整数を渡すと、結果はスカラーになります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PvILXc1PjqTM"
      },
      "outputs": [],
      "source": [
        "# Pull out a single value from a 2-rank tensor\n",
        "print(rank_2_tensor[1, 1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3RLCzAOHjfEH"
      },
      "source": [
        "整数とスライスを任意に組み合わせてインデックスを作成することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YTqNqsfJkJP_"
      },
      "outputs": [],
      "source": [
        "# Get row and column tensors\n",
        "print(\"Second row:\", rank_2_tensor[1, :].numpy())\n",
        "print(\"Second column:\", rank_2_tensor[:, 1].numpy())\n",
        "print(\"Last row:\", rank_2_tensor[-1, :].numpy())\n",
        "print(\"First item in last column:\", rank_2_tensor[0, -1].numpy())\n",
        "print(\"Skip the first row:\")\n",
        "print(rank_2_tensor[1:, :].numpy(), \"\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P45TwSUVSK6G"
      },
      "source": [
        "次は、3 軸テンソルを使用した例です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GuLoMoCVSLxK"
      },
      "outputs": [],
      "source": [
        "print(rank_3_tensor[:, :, 4])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9NgmHq27TJOE"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "<th colspan=\"2\">バッチ内の各例のすべての位置で最後の特徴量を選択する</th>\n",
        "</tr>\n",
        "<tr>\n",
        "    <td> <img src=\"images/tensor/index1.png\" alt=\"A 3x2x5 tensor with all the values at the index-4 of the last axis selected.\">\n",
        "</td>\n",
        "      <td> <img src=\"images/tensor/index2.png\" alt=\"The selected values packed into a 2-axis tensor.\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fpr7R0t4SVb0"
      },
      "source": [
        "## 形状の操作\n",
        "\n",
        "テンソルの形状変更は非常に便利です。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EMeTtga5Wq8j"
      },
      "outputs": [],
      "source": [
        "# Shape returns a `TensorShape` object that shows the size on each dimension\n",
        "var_x = tf.Variable(tf.constant([[1], [2], [3]]))\n",
        "print(var_x.shape)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "38jc2RXziT3W"
      },
      "outputs": [],
      "source": [
        "# You can convert this object into a Python list, too\n",
        "print(var_x.shape.as_list())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "J_xRlHZMKYnF"
      },
      "source": [
        "テンソルを新しい形状に変更できます。<code>tf.reshape</code> 演算は、基盤のデータを複製する必要がないため、素早く簡単に行えます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pa9JCgMLWy87"
      },
      "outputs": [],
      "source": [
        "# We can reshape a tensor to a new shape.\n",
        "# Note that we're passing in a list\n",
        "reshaped = tf.reshape(var_x, [1, 3])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Mcq7iXOkW3LK"
      },
      "outputs": [],
      "source": [
        "print(var_x.shape)\n",
        "print(reshaped.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gIB2tOkoVr6E"
      },
      "source": [
        "データはレイアウトをメモリに維持したまま、同じデータにポイントする新しいテンソルが要求された形状で作成されます。TensorFlow は C 形式の「行優先」メモリ順序付けを使用しており、右端のインデックスの増分は、メモリ内の 1 ステップに相当します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7kMfM0RpUgI8"
      },
      "outputs": [],
      "source": [
        "print(rank_3_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TcDtfQkJWzIx"
      },
      "source": [
        "テンソルをフラット化すると、どの順序jでメモリにレイアウトされているかを確認できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "COnHEPuaWDQp"
      },
      "outputs": [],
      "source": [
        "# A `-1` passed in the `shape` argument says \"Whatever fits\".\n",
        "print(tf.reshape(rank_3_tensor, [-1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jJZRira2W--c"
      },
      "source": [
        "通常、` tf.reshape ` の唯一合理的な使用は、隣接する軸を結合または分割する（または `1` を追加/削除する）ことです。\n",
        "\n",
        "この 3x2x5 のテンソルでは、スライスは混合しないため、(3x2)x5 または 3x(2x5) に形状を変更するのが合理的です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zP2Iqc7zWu_J"
      },
      "outputs": [],
      "source": [
        "print(tf.reshape(rank_3_tensor, [3*2, 5]), \"\\n\")\n",
        "print(tf.reshape(rank_3_tensor, [3, -1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6ZsZRUhihlDB"
      },
      "source": [
        "<table>\n",
        "<th colspan=\"3\"> 形状変更の成功例。</th>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/reshape-before.png\" alt=\"A 3x2x5 tensor\">\n",
        "</td>\n",
        "  <td>   <img src=\"images/tensor/reshape-good1.png\" alt=\"The same data reshaped to (3x2)x5\">\n",
        "</td>\n",
        "  <td> <img src=\"images/tensor/reshape-good2.png\" alt=\"The same data reshaped to 3x(2x5)\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nOcRxDC3jNIU"
      },
      "source": [
        "形状変更は要素の総数が等しい新しい形状で「機能」しますが、軸の順を守らなければ役に立ちません。\n",
        "\n",
        "`tf.reshape` では軸の交換は機能しないため、それを行うには `tf.transpose` が必要です。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "I9qDL_8u7cBH"
      },
      "outputs": [],
      "source": [
        "# Bad examples: don't do this\n",
        "\n",
        "# You can't reorder axes with reshape.\n",
        "print(tf.reshape(rank_3_tensor, [2, 3, 5]), \"\\n\") \n",
        "\n",
        "# This is a mess\n",
        "print(tf.reshape(rank_3_tensor, [5, 6]), \"\\n\")\n",
        "\n",
        "# This doesn't work at all\n",
        "try:\n",
        "  tf.reshape(rank_3_tensor, [7, -1])\n",
        "except Exception as e:\n",
        "  print(f\"{type(e).__name__}: {e}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qTM9-5eh68oo"
      },
      "source": [
        "<table>\n",
        "<th colspan=\"3\">形状変更の失敗例。</th>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/reshape-bad.png\" alt=\"You can't reorder axes, use tf.transpose for that\">   </td>\n",
        "  <td> <img src=\"images/tensor/reshape-bad4.png\" alt=\"Anything that mixes the slices of data together is probably wrong.\">\n",
        "</td>\n",
        "  <td> <img src=\"images/tensor/reshape-bad2.png\" alt=\"The new shape must fit exactly.\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N9r90BvHCbTt"
      },
      "source": [
        "不完全に指定された形状を実行することができます。その形状には `None`（次元の長さが不明）が含まれているか、形状が `None`（テンソルの階数が不明）であるかのいずれかです。\n",
        "\n",
        "[tf.RaggedTensor](#ragged_tensors) を除き、これは TensorFlow の象徴的なグラフ構築 API の文脈で発生します。\n",
        "\n",
        "- [tf.function](function.ipynb)\n",
        "- [Keras 関数型 API](keras/functional.ipynb)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fDmFtFM7k0R2"
      },
      "source": [
        "## `DTypes` をさらに詳しく\n",
        "\n",
        "`tf.Tensor` のデータ型を検査するには、`Tensor.dtype` プロパティを使用します。\n",
        "\n",
        "Python オブジェクトから `tf.Tensor` を作成する場合、オプションとしてデータ型を指定できます。\n",
        "\n",
        "指定しない場合は、TensorFlow によってデータを表すデータ型が選択されます。TensorFlow は Python の整数値を `tf.int32` と Python 浮動小数点数を `tf.float32` に変換します。そうでない場合は、TensorFlow は NumPy が配列に変換する場合と同じルールを使用します。\n",
        "\n",
        "型から型にキャストすることができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5mSTDWbelUvu"
      },
      "outputs": [],
      "source": [
        "the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)\n",
        "the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)\n",
        "# Now, let's cast to an uint8 and lose the decimal precision\n",
        "the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)\n",
        "print(the_u8_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "s1yBlJsVlFSu"
      },
      "source": [
        "## ブロードキャスト\n",
        "\n",
        "ブロードキャストは、[NumPy の相当する機能](https://numpy.org/doc/stable/user/basics.html)から得た概念です。簡単に言えば、ある条件下において、より小さなテンソルに複合演算を実行する場合、より大きなテンソルに適合するように自動的に「引き延ばされる」ということです。\n",
        "\n",
        "最も単純で一般的な事例としては、テンソルをスカラーに加算または乗算する場合が挙げられます。その場合、スカラーはもう片方の引数と同じ形状になるようにブロードキャストされます。 "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "P8sypqmagHQN"
      },
      "outputs": [],
      "source": [
        "x = tf.constant([1, 2, 3])\n",
        "\n",
        "y = tf.constant(2)\n",
        "z = tf.constant([2, 2, 2])\n",
        "# All of these are the same computation\n",
        "print(tf.multiply(x, 2))\n",
        "print(x * y)\n",
        "print(x * z)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o0SBoR6voWcb"
      },
      "source": [
        "同様に、1 にサイズ設定された次元を別の引数に一致するように引き延ばすことができます。両方の引数を同一の計算で引き延ばすことができます。\n",
        "\n",
        "この場合、3x1 の行列は、要素ごとに 1x4 の行列と乗算され、3x4 の行列が生成されます。最初の 1 はオプションであることに注意してください。形状 y は `[4]` です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6sGmkPg3XANr"
      },
      "outputs": [],
      "source": [
        "# These are the same computations\n",
        "x = tf.reshape(x,[3,1])\n",
        "y = tf.range(1, 5)\n",
        "print(x, \"\\n\")\n",
        "print(y, \"\\n\")\n",
        "print(tf.multiply(x, y))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "t_7sh-EUYLrE"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>ブロードキャストの加算: <code>[3, 1]</code> 掛け <code>[1, 4]</code> により、<code>[3,4]</code> を生成</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/broadcasting.png\" alt=\"Adding a 3x1 matrix to a 4x1 matrix results in a 3x4 matrix\">   </td>\n",
        "</tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9V3KgSJcKDRz"
      },
      "source": [
        "次は、ブロードキャストを使用しない同一の演算です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "elrF6v63igY8"
      },
      "outputs": [],
      "source": [
        "x_stretch = tf.constant([[1, 1, 1, 1],\n",
        "                         [2, 2, 2, 2],\n",
        "                         [3, 3, 3, 3]])\n",
        "\n",
        "y_stretch = tf.constant([[1, 2, 3, 4],\n",
        "                         [1, 2, 3, 4],\n",
        "                         [1, 2, 3, 4]])\n",
        "\n",
        "print(x_stretch * y_stretch)  # Again, operator overloading"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "14KobqYu85gi"
      },
      "source": [
        "ブロードキャスト演算によってメモリ内の拡張したテンソルが実体化されることがないため、ほとんどの場合、ブロードキャストは時間と空間係数の両方です。\n",
        "\n",
        "`tf.broadcast_to` を使用して、ブロードキャストがどのようなものであるかを確認します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GW2Q59_r8hZ6"
      },
      "outputs": [],
      "source": [
        "print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z2bAMMQY-jpP"
      },
      "source": [
        "たとえば数学的演算とは異なり、`broadcast_to` はメモリを節約する上で何も特別なことは実行しません。ここでは、テンソルの実体化が行われています。\n",
        "\n",
        "さらに複雑化することができます。Jake VanderPlas の書籍『*Python Data Science Handbook*』の[このセクション](https://jakevdp.github.io/PythonDataScienceHandbook/02.05-computation-on-arrays-broadcasting.html)では、ブロードキャストのコツがさらに紹介されています（やはり NumPy で）。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o4Rpz0xAsKSI"
      },
      "source": [
        "## tf.convert_to_tensor\n",
        "\n",
        "`tf.matmul` や `tf.reshape` といったほとんどの演算は、クラス `tf.Tensor` の引数を取りますが、上記の例では、テンソルのような形状の Python オブジェクトを渡すことがよくあります。\n",
        "\n",
        "すべてではありませんが、ほとんどの演算は、非テンソル引数に対して `convert_to_tensor` を呼び出します。変換のレジストリがあり、NumPy の `ndarray`、`TensorShape`、Python リスト、`tf.Variable` といったほとんどのオブジェクトクラスは、自動的に変換されます。\n",
        "\n",
        "詳細について、または、テンソルに自動変換する独自の型がある場合は、`tf.register_tensor_conversion_function` を参照してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "05bBVBVYV0y6"
      },
      "source": [
        "## 不規則なテンソル\n",
        "\n",
        "軸に合わせて要素の数が変化するテンソルは「不規則」と呼ばれています。不規則なデータには、`tf.ragged.RaggedTensor` を使用してください。\n",
        "\n",
        "たとえば、次の形状は通常のテンソルとして表現することはできません。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VPc3jGoeJqB7"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>`tf.RaggedTensor`, 形状: <code>[4, None]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/ragged.png\" alt=\"A 2-axis ragged tensor, each row can have a different length.\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VsbTjoFfNVBF"
      },
      "outputs": [],
      "source": [
        "ragged_list = [\n",
        "    [0, 1, 2, 3],\n",
        "    [4, 5],\n",
        "    [6, 7, 8],\n",
        "    [9]]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "p4xKTo57tutG"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "  tensor = tf.constant(ragged_list)\n",
        "except Exception as e:\n",
        "  print(f\"{type(e).__name__}: {e}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0cm9KuEeMLGI"
      },
      "source": [
        "代わりに、`tf.ragged.constant` を使用して `tf.RaggedTensor` を作成します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "XhF3QV3jiqTj"
      },
      "outputs": [],
      "source": [
        "ragged_tensor = tf.ragged.constant(ragged_list)\n",
        "print(ragged_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sFgHduHVNoIE"
      },
      "source": [
        "`tf.RaggedTensor` の形状には不明な次元が含まれます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Eo_3wJUWNgqB"
      },
      "outputs": [],
      "source": [
        "print(ragged_tensor.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V9njclVkkN7G"
      },
      "source": [
        "## 文字列型テンソル\n",
        "\n",
        "`tf.string` は `dtype` であるため、テンソルで文字列（可変長バイト配列）としてデータを表すことができます。\n",
        "\n",
        "文字列はアトミックであり、Python 文字列のようにインデックスを作成することはできません。文字列の長さはテンソルの次元の 1 つではありません。これらを操作するための関数については、`tf.strings` を参照してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5P_8spEGQ0wp"
      },
      "source": [
        "次はスカラー文字列のテンソルです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sBosmM8MkIh4"
      },
      "outputs": [],
      "source": [
        "# Tensors can be strings, too here is a scalar string.\n",
        "scalar_string_tensor = tf.constant(\"Gray wolf\")\n",
        "print(scalar_string_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CMFBSl1FQ3vE"
      },
      "source": [
        "そして、ベクトルの文字列です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IO-c3Tq3RC1L"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>文字列ベクトル, 形状: <code>[3,]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/strings.png\" alt=\"The string length is not one of the tensor's axes.\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "41Dv2kL9QrtO"
      },
      "outputs": [],
      "source": [
        "# If you have three string tensors of different lengths, this is OK.\n",
        "tensor_of_strings = tf.constant([\"Gray wolf\",\n",
        "                                 \"Quick brown fox\",\n",
        "                                 \"Lazy dog\"])\n",
        "# Note that the shape is (3,). The string length is not included.\n",
        "print(tensor_of_strings)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "76gQ9qrgSMzS"
      },
      "source": [
        "上記の出力では、プレフィクス `b` は `tf.string` dtype が unicode 文字列でなくバイト文字列であることを示します。TensorFlow での Unicode テキストの使用については、「[Unicode チュートリアル](https://www.tensorflow.org/tutorials/load_data/unicode)」 を参照してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ClSBPK-lZBQp"
      },
      "source": [
        "Unicode 文字を渡した場合、utf-8 で暗号化されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GTgL53jxSMd9"
      },
      "outputs": [],
      "source": [
        "tf.constant(\"🥳👍\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ir9cY42MMAei"
      },
      "source": [
        "文字列の基本的な関数は、`tf.strings.split` などの `tf.strings` を使って見つけることができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8k2K0VTFyj8e"
      },
      "outputs": [],
      "source": [
        "# We can use split to split a string into a set of tensors\n",
        "print(tf.strings.split(scalar_string_tensor, sep=\" \"))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zgGAn1dfR-04"
      },
      "outputs": [],
      "source": [
        "# ...but it turns into a `RaggedTensor` if we split up a tensor of strings,\n",
        "# as each string might be split into a different number of parts.\n",
        "print(tf.strings.split(tensor_of_strings))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HsAn1kPeO84m"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th> 3 文字列分割, 形状: <code>[3, None]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/string-split.png\" alt=\"Splitting multiple strings returns a tf.RaggedTensor\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "st9OxrUxWSKY"
      },
      "source": [
        "また、`tf.string.to_number` も利用できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3nRtx3X9WRfN"
      },
      "outputs": [],
      "source": [
        "text = tf.constant(\"1 10 100\")\n",
        "print(tf.strings.to_number(tf.strings.split(text, \" \")))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "r2EZtBbJBns4"
      },
      "source": [
        "`tf.cast` を使用して文字列テンソルを数値に変換することはできませんが、バイトに変換してから数字に変換することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fo8BjmH7gyTj"
      },
      "outputs": [],
      "source": [
        "byte_strings = tf.strings.bytes_split(tf.constant(\"Duck\"))\n",
        "byte_ints = tf.io.decode_raw(tf.constant(\"Duck\"), tf.uint8)\n",
        "print(\"Byte strings:\", byte_strings)\n",
        "print(\"Bytes:\", byte_ints)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uSQnZ7d1jCSQ"
      },
      "outputs": [],
      "source": [
        "# Or split it up as unicode and then decode it\n",
        "unicode_bytes = tf.constant(\"アヒル 🦆\")\n",
        "unicode_char_bytes = tf.strings.unicode_split(unicode_bytes, \"UTF-8\")\n",
        "unicode_values = tf.strings.unicode_decode(unicode_bytes, \"UTF-8\")\n",
        "\n",
        "print(\"\\nUnicode bytes:\", unicode_bytes)\n",
        "print(\"\\nUnicode chars:\", unicode_char_bytes)\n",
        "print(\"\\nUnicode values:\", unicode_values)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fE7nKJ2YW3aY"
      },
      "source": [
        "TensorFlow ではすべての生のバイトに、`tf.string` dtype が使用されています。`tf.io` モジュールには、画像の解読や csv の解析など、データとバイトを変換する関数が含まれています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ua8BnAzxkRKV"
      },
      "source": [
        "## スパーステンソル\n",
        "\n",
        "非常に広い埋め込みスペースであるかのうように、データがスパースである場合があります。TensorFlow は、スパースデータを効率的に保管できるように、`tf.sparse.SparseTensor` と関連する演算をサポートしています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mS5zgqgUTPRb"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>`tf.SparseTensor`, 形状: <code>[3, 4]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img src=\"images/tensor/sparse.png\" alt=\"An 3x4 grid, with values in only two of the cells.\">   </td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "B9nbO1E2kSUN"
      },
      "outputs": [],
      "source": [
        "# Sparse tensors store values by index in a memory-efficient manner\n",
        "sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],\n",
        "                                       values=[1, 2],\n",
        "                                       dense_shape=[3, 4])\n",
        "print(sparse_tensor, \"\\n\")\n",
        "\n",
        "# We can convert sparse tensors to dense\n",
        "print(tf.sparse.to_dense(sparse_tensor))"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "Tce3stUlHN0L"
      ],
      "name": "tensor.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
